<template>
  <div class="chart-wrapper">
    <canvas ref="chartCanvas"></canvas>
  </div>
</template>

<script setup>
import { ref, onMounted, watch, onBeforeUnmount } from 'vue';

// 定义 props
const props = defineProps({
  data: {
    type: Array,
    required: true,
    validator: (value) => value.every((item) => item.value > 0), // 确保每个数据点的值大于 0
  },
  options: {
    type: Object,
    default: () => ({}),
  },
});

// 默认配置
const defaultOptions = {
  minRadius: 10, // 最小气泡半径
  maxRadius: 50, // 最大气泡半径
  minColor: '#a1c4fd', // 最小数值对应的颜色（浅色）
  maxColor: '#2a5298', // 最大数值对应的颜色（深色）
  backgroundColor: '#1e3c72', // 背景颜色
  padding: 40, // 画布内边距
  labelColor: '#ffffff', // 标签颜色
  labelFont: '12px Arial', // 标签字体
  axisColor: '#ffffff', // 轴线颜色
  gridColor: 'rgba(255, 255, 255, 0.1)', // 网格线颜色
  lightSource: { x: 0.2, y: 0.2 }, // 光源位置（相对坐标）
};

// 合并配置
const chartOptions = {
  ...defaultOptions,
  ...props.options,
};

// 引用 canvas 元素
const chartCanvas = ref(null);
let ctx = null; // canvas 上下文

// 初始化 canvas
const initCanvas = () => {
  if (chartCanvas.value) {
    const parent = chartCanvas.value.parentElement;
    chartCanvas.value.width = parent.clientWidth; // 宽度充满父容器
    chartCanvas.value.height = parent.clientHeight; // 高度充满父容器
    ctx = chartCanvas.value.getContext('2d');
    renderChart();
  }
};

// 计算气泡半径
const calculateRadius = (value, minValue, maxValue) => {
  const { minRadius, maxRadius } = chartOptions;
  return minRadius + ((value - minValue) / (maxValue - minValue)) * (maxRadius - minRadius);
};

// 计算气泡颜色
const calculateColor = (value, minValue, maxValue) => {
  const { minColor, maxColor } = chartOptions;
  const ratio = (value - minValue) / (maxValue - minValue);
  const r = Math.round(parseInt(minColor.slice(1, 3), 16) + (parseInt(maxColor.slice(1, 3), 16) - parseInt(minColor.slice(1, 3), 16)) * ratio);
  const g = Math.round(parseInt(minColor.slice(3, 5), 16) + (parseInt(maxColor.slice(3, 5), 16) - parseInt(minColor.slice(3, 5), 16)) * ratio);
  const b = Math.round(parseInt(minColor.slice(5, 7), 16) + (parseInt(maxColor.slice(5, 7), 16) - parseInt(minColor.slice(5, 7), 16)) * ratio);
  return `rgb(${r}, ${g}, ${b})`;
};

// 绘制背景
const drawBackground = () => {
  const { width, height, backgroundColor } = chartOptions;
  ctx.fillStyle = backgroundColor;
  ctx.fillRect(0, 0, width, height);
};

// 绘制网格线和刻度
const drawGridAndAxes = () => {
  const { width, height, padding, axisColor, gridColor } = chartOptions;
  const maxValue = Math.max(...props.data.map((item) => item.value));

  // 绘制 Y 轴
  ctx.strokeStyle = axisColor;
  ctx.beginPath();
  ctx.moveTo(padding, padding); // Y 轴起点
  ctx.lineTo(padding, height - padding); // Y 轴终点
  ctx.stroke();

  // 绘制 X 轴
  ctx.beginPath();
  ctx.moveTo(padding, height - padding); // X 轴起点
  ctx.lineTo(width - padding, height - padding); // X 轴终点
  ctx.stroke();

  // 绘制网格线
  ctx.strokeStyle = gridColor;
  ctx.lineWidth = 0.5;
  const yStep = (height - 2 * padding) / 5; // Y 轴网格线间距
  for (let i = 0; i <= 5; i++) {
    const y = height - padding - i * yStep;
    ctx.beginPath();
    ctx.moveTo(padding, y);
    ctx.lineTo(width - padding, y);
    ctx.stroke();
  }

  // 绘制 Y 轴刻度标签
  ctx.fillStyle = axisColor;
  ctx.font = '12px Arial';
  ctx.textAlign = 'right';
  for (let i = 0; i <= 5; i++) {
    const value = (maxValue / 5) * i;
    const y = height - padding - i * yStep;
    ctx.fillText(value.toFixed(0), padding - 10, y + 4);
  }
};

// 绘制 3D 气泡
const drawBubbles = () => {
  const { width, height, padding, labelColor, labelFont, lightSource } = chartOptions;
  const values = props.data.map((item) => item.value);
  const minValue = Math.min(...values);
  const maxValue = Math.max(...values);

  ctx.font = labelFont;
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';

  props.data.forEach((item) => {
    const { label, value } = item;
    const radius = calculateRadius(value, minValue, maxValue);
    const color = calculateColor(value, minValue, maxValue);

    // 随机生成气泡位置（确保不超出画布范围）
    const x = padding + Math.random() * (width - 2 * padding - 2 * radius);
    const y = padding + Math.random() * (height - 2 * padding - 2 * radius);

    // 创建径向渐变（模拟 3D 光照效果）
    const gradient = ctx.createRadialGradient(
        x + radius * lightSource.x, // 光源 X 位置
        y + radius * lightSource.y, // 光源 Y 位置
        radius * 0.1, // 光源半径
        x + radius, // 气泡中心 X
        y + radius, // 气泡中心 Y
        radius // 气泡半径
    );
    gradient.addColorStop(0, 'rgba(255, 255, 255, 0.8)'); // 高光
    gradient.addColorStop(0.5, color); // 主色
    gradient.addColorStop(1, 'rgba(0, 0, 0, 0.5)'); // 阴影

    // 绘制气泡
    ctx.beginPath();
    ctx.arc(x + radius, y + radius, radius, 0, Math.PI * 2);
    ctx.fillStyle = gradient;
    ctx.fill();

    // 绘制标签
    ctx.fillStyle = labelColor;
    ctx.fillText(label, x + radius, y + radius);
  });
};

// 渲染图表
const renderChart = () => {
  if (!chartCanvas.value) return;

  // 清空画布
  ctx.clearRect(0, 0, chartCanvas.value.width, chartCanvas.value.height);

  // 更新配置中的宽度和高度
  chartOptions.width = chartCanvas.value.width;
  chartOptions.height = chartCanvas.value.height;

  // 绘制背景、网格线、轴线和气泡
  drawBackground();
  drawGridAndAxes();
  drawBubbles();
};

// 监听数据变化
watch(
    () => props.data,
    () => {
      renderChart();
    },
    { deep: true }
);

// 组件挂载时初始化
onMounted(() => {
  initCanvas();
  window.addEventListener('resize', initCanvas); // 监听窗口大小变化
});

// 组件卸载时移除监听器
onBeforeUnmount(() => {
  window.removeEventListener('resize', initCanvas);
});
</script>

<style scoped>
.chart-wrapper {
  width: 100%;
  height: 100%;
}
</style>